import com.intellij.ide.util.PackageChooserDialog;
import com.intellij.notification.*;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiPackage;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @description: 删除没有引用的类
 * @author: chengsheng@qbb6.com
 * @date: 2018/12/1
 */
public class RmUnusedClass extends AnAction {

    private static NotificationGroup notificationGroup;

    static{
        notificationGroup = new NotificationGroup("Java2Json.NotificationGroup", NotificationDisplayType.BALLOON, true);
    }

    @Override
    public void actionPerformed(AnActionEvent e) {
        final Project project = CommonDataKeys.PROJECT.getData(e.getDataContext());
        try {
            PackageChooserDialog chooser = new PackageChooserDialog("Choose packages", project);
            chooser.show();
            final List<PsiPackage> packages = chooser.getSelectedPackages();
            if (packages.size() > 0) {
                List<PsiPackage> copyOnWriteArrayList=new CopyOnWriteArrayList();
                copyOnWriteArrayList=getPackages(copyOnWriteArrayList,packages);
                ConcurrentMap concurrentMap = removeClass(project, copyOnWriteArrayList);
                Notification info=null;
                if (concurrentMap.size() > 0) {
                    info=notificationGroup.createNotification("Success remove class:" + concurrentMap, NotificationType.INFORMATION);
                   Notifications.Bus.notify(info, project);
                } else {
                   info= notificationGroup.createNotification("No class unused!", NotificationType.INFORMATION);
                    Notifications.Bus.notify(info, project);
                }

            }
        }catch (Exception ex){
            Notification error=notificationGroup.createNotification("remove unused class error", NotificationType.ERROR);
            Notifications.Bus.notify(error, project);
        }
    }


    public List<PsiPackage> getPackages(List<PsiPackage> copyOnWriteArrayList,List<PsiPackage> packages) {
        packages.stream().forEach(apackage->{
            copyOnWriteArrayList.add(apackage);
            PsiPackage[] psiPackages= apackage.getSubPackages();
            if(psiPackages.length>0){
                List<PsiPackage> psiPackageList = new ArrayList<>(Arrays.asList(psiPackages));
                getPackages(copyOnWriteArrayList,psiPackageList);
            }
        });
        return copyOnWriteArrayList;
    }

    public ConcurrentMap removeClass(Project project,List<PsiPackage> psiPackages){
        ConcurrentHashMap concurrentHashMap=new ConcurrentHashMap();
        psiPackages.stream().forEach(aPackage ->{
            List<PsiClass> psiClasses = new ArrayList<>(Arrays.asList(aPackage.getClasses()));
            if(psiClasses.size()>0){
                Iterator<PsiClass> iterable = psiClasses.iterator();

                CopyOnWriteArrayList<String> filesName=new CopyOnWriteArrayList<>();
                while (iterable.hasNext()){
                    PsiClass psiClass=(PsiClass)iterable.next();
                    Long count=  ReferencesSearch.search(psiClass).findAll().stream().count();
                    if(count==0){
                        iterable.remove();
                        WriteCommandAction.runWriteCommandAction(project,() ->{
                            psiClass.delete();
                            filesName.add(psiClass.getName());
                        });
                    }
                }
                concurrentHashMap.put(aPackage.getQualifiedName(),filesName);
            }
        });
        return concurrentHashMap;
    }
}
